home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -in_the_mag- / emulation / amiga / uae-0.7.0b2 / src / main.c < prev    next >
C/C++ Source or Header  |  1998-01-20  |  28KB  |  955 lines

  1.  /*
  2.   * UAE - The Un*x Amiga Emulator
  3.   *
  4.   * Main program
  5.   *
  6.   * Copyright 1995 Ed Hanway
  7.   * Copyright 1995, 1996, 1997 Bernd Schmidt
  8.   */
  9.  
  10. #include "sysconfig.h"
  11. #include "sysdeps.h"
  12. #include <assert.h>
  13.  
  14. #include "config.h"
  15. #include "options.h"
  16. #include "threaddep/penguin.h"
  17. #include "uae.h"
  18. #include "gensound.h"
  19. #include "sounddep/sound.h"
  20. #include "events.h"
  21. #include "memory.h"
  22. #include "custom.h"
  23. #include "serial.h"
  24. #include "readcpu.h"
  25. #include "newcpu.h"
  26. #include "disk.h"
  27. #include "debug.h"
  28. #include "xwin.h"
  29. #include "joystick.h"
  30. #include "keybuf.h"
  31. #include "gui.h"
  32. #include "zfile.h"
  33. #include "autoconf.h"
  34. #include "osemu.h"
  35. #include "osdep/exectasks.h"
  36. #include "compiler.h"
  37. #include "picasso96.h"
  38. #include "uaeexe.h"
  39.  
  40. int version = 100*UAEMAJOR + 10*UAEMINOR + UAEURSAMINOR;
  41.  
  42. /* Note to porters: please don't change any of these options! UAE is supposed
  43.  * to behave identically on all platforms if possible. */
  44. struct uae_prefs currprefs = {
  45. /* framerate */ 1,
  46. /* illegal_mem */ 0,
  47. /* no_xhair */ 0,
  48. /* use_serial */ 0,
  49. /* serial_demand */ 0,
  50. /* parallel_demand */ 0,
  51. /* automount_uaedev */ 1,
  52.  
  53. /* fake_joystick */ 2 + (0<<8),
  54. /* KbdLang keyboard_lang */ KBD_LANG_US,
  55. /* allow_save */ 0,
  56. /* emul_accuracy */ 2,
  57. /* test_drawing_speed */ 0,
  58.  
  59. /* produce_sound */ 0,
  60. /* stereo */ 0,
  61. /* sound_bits */ DEFAULT_SOUND_BITS,
  62. /* sound_freq */ DEFAULT_SOUND_FREQ,
  63. /* sound_minbsiz */ DEFAULT_SOUND_MINB,
  64. /* sound_maxbsiz */ DEFAULT_SOUND_MAXB,
  65.  
  66. /* gfx_width */ 800,
  67. /* gfx_height */ 600,
  68. /* gfx_lores */ 0,
  69. /* gfx_linedbl */ 0,
  70. /* gfx_correct_aspect */ 0,
  71. /* gfx_xcenter */ 0,
  72. /* gfx_ycenter */ 0,
  73. /* color_mode */ 0,
  74.  
  75. /* use_low_bandwidth */ 0,
  76. /* use_mitshm */ 0,
  77.  
  78. /* immediate_blits */ 0,
  79. /* blits_32bit_enabled */ 0,
  80.  
  81. /* floppies */ { "df0.adf", "df1.adf", "df2.adf", "df3.adf" },
  82.  
  83. /* copper_pos */ -1,
  84. /* m68k_speed */ 4
  85. };
  86. struct uae_prefs changed_prefs;
  87.  
  88. int no_gui = 0, use_debugger = 0, use_gfxlib = 0;
  89.  
  90. int joystickpresent = 0;
  91.  
  92. int cloanto_rom = 0;
  93.  
  94. char warning_buffer[256];
  95.  
  96. uae_u32 fastmem_size = 0x00000000;
  97. uae_u32 a3000mem_size = 0x00000000;
  98. uae_u32 z3fastmem_size = 0x00000000;
  99. uae_u32 chipmem_size = 0x00200000;
  100. uae_u32 bogomem_size = 0x00000000;
  101. uae_u32 gfxmem_size = 0x00000000;
  102.  
  103. int address_space_24 = CPU_LEVEL > 1 ? 0 : 1;
  104. char romfile[256] = "kick.rom";
  105. char keyfile[256] = "";
  106. char prtname[256] = DEFPRTNAME;
  107.  
  108. char optionsfile[256];
  109.  
  110. /* If you want to pipe printer output to a file, put something like
  111.  * "cat >>printerfile.tmp" above.
  112.  * The printer support was only tested with the driver "PostScript" on
  113.  * Amiga side, using apsfilter for linux to print ps-data.
  114.  *
  115.  * Under DOS it ought to be -p LPT1: or -p PRN: but you'll need a
  116.  * PostScript printer or ghostscript -=SR=-
  117.  */
  118.  
  119. /* People must provide their own name for this */
  120. char sername[256] = "";
  121.  
  122. /* Slightly stupid place for this... */
  123. /* ncurses.c might use quite a few of those. */
  124. char *colormodes[] = { "256 colors", "32768 colors", "65536 colors",
  125.     "256 colors dithered", "16 colors dithered", "16 million colors",
  126.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  127.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  128.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  129.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  130.     "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""
  131. };
  132.  
  133. static void fix_options(void)
  134. {
  135.     int err = 0;
  136.  
  137.     if (address_space_24 != 0 && address_space_24 != 1) {
  138.     fprintf (stderr, "The option -4 requires either 1 or 0 as argument.\n");
  139.     err = 1;
  140.     address_space_24 = 0;
  141.     }
  142.  
  143.     if ((chipmem_size & (chipmem_size - 1)) != 0
  144.     || chipmem_size < 0x80000
  145.     || chipmem_size > 0x800000)
  146.     {
  147.     chipmem_size = 0x200000;
  148.     fprintf (stderr, "Unsupported chipmem size!\n");
  149.     err = 1;
  150.     }
  151.     if ((fastmem_size & (fastmem_size - 1)) != 0
  152.     || (fastmem_size != 0 && (fastmem_size < 0x100000 || fastmem_size > 0x800000)))
  153.     {
  154.     fastmem_size = 0;
  155.     fprintf (stderr, "Unsupported fastmem size!\n");
  156.     err = 1;
  157.     }
  158.     if ((gfxmem_size & (gfxmem_size - 1)) != 0
  159.     || (gfxmem_size != 0 && (gfxmem_size < 0x100000 || gfxmem_size > 0x800000)))
  160.     {
  161.     gfxmem_size = 0;
  162.     fprintf (stderr, "Unsupported graphics card memory size!\n");
  163.     err = 1;
  164.     }
  165.     if ((z3fastmem_size & (z3fastmem_size - 1)) != 0
  166.     || (z3fastmem_size != 0 && (z3fastmem_size < 0x100000 || z3fastmem_size > 0x4000000)))
  167.     {
  168.     z3fastmem_size = 0;
  169.     fprintf (stderr, "Unsupported Zorro III fastmem size!\n");
  170.     err = 1;
  171.     }
  172.     if (address_space_24 && (gfxmem_size != 0 || z3fastmem_size != 0)) {
  173.     z3fastmem_size = gfxmem_size = 0;
  174.     fprintf (stderr, "Can't use a graphics card or Zorro III fastmem when using a 24 bit\n"
  175.          "address space - sorry.\n");
  176.     }
  177.     if ((bogomem_size & (bogomem_size - 1)) != 0
  178.     || (bogomem_size != 0 && (bogomem_size < 0x80000 || bogomem_size > 0x100000)))
  179.     {
  180.     bogomem_size = 0;
  181.     fprintf (stderr, "Unsupported bogomem size!\n");
  182.     err = 1;
  183.     }
  184.  
  185.     if (chipmem_size > 0x200000 && fastmem_size != 0) {
  186.     fprintf (stderr, "You can't use fastmem and more than 2MB chip at the same time!\n");
  187.     fastmem_size = 0;
  188.     err = 1;
  189.     }
  190.     if (currprefs.copper_pos < -1 || currprefs.copper_pos > 224) {
  191.     fprintf (stderr, "Bad copper position specified (must be 0..224 or -1)\n");
  192.     currprefs.copper_pos = -1;
  193.     err = 1;
  194.     }
  195.     if (currprefs.m68k_speed < 1 || currprefs.m68k_speed > 20) {
  196.     fprintf (stderr, "Bad value for -w parameter: must be within 1..20.\n");
  197.     currprefs.m68k_speed = 4;
  198.     err = 1;
  199.     }
  200.     if (currprefs.produce_sound < 0 || currprefs.produce_sound > 3) {
  201.     fprintf (stderr, "Bad value for -S parameter: enable value must be within 0..3\n");
  202.     currprefs.produce_sound = 0;
  203.     err = 1;
  204.     }
  205.  
  206.     if (err)
  207.     fprintf (stderr, "Please use \"uae -h\" to get usage information.\n");
  208. }
  209.  
  210. int quit_program = 0;
  211.  
  212. void uae_reset (void)
  213. {
  214.     if (quit_program != 1 && quit_program != -1)
  215.     quit_program = -2;
  216. }
  217.  
  218. void uae_quit (void)
  219. {
  220.     if (quit_program != -1)
  221.     quit_program = -1;
  222. }
  223.  
  224. /*
  225.  * This function is dangerous, at least if you use different versions of UAE
  226.  * from time to time (as I do). For example, running the SVGAlib version with
  227.  * "-o" will discard the keyboard language information...
  228.  */
  229. void save_options(FILE *f)
  230. {
  231.     /* We only get here if allow_save is true, so... */
  232.     fprintf (f, "-o\n");
  233.     if (use_debugger)
  234.     fprintf (f, "-D\n");
  235.     fprintf (f, "-r %s\n", romfile);
  236.     if (strlen (keyfile) > 0)
  237.     fprintf (f, "-K %s\n", keyfile);
  238.     fprintf (f, "-0 %s\n", currprefs.df[0]);
  239.     fprintf (f, "-1 %s\n", currprefs.df[1]);
  240.     fprintf (f, "-2 %s\n", currprefs.df[2]);
  241.     fprintf (f, "-3 %s\n", currprefs.df[3]);
  242. #ifndef UNSUPPORTED_OPTION_p
  243.     fprintf (f, "-p %s\n", prtname);
  244. #endif
  245. #ifndef UNSUPPORTED_OPTION_S
  246.     fprintf (f, "-S %d:%c:%d:%d:%d:%d\n", currprefs.produce_sound,
  247.         currprefs.stereo ? 's' : 'm',
  248.         currprefs.sound_bits,
  249.         currprefs.sound_freq,
  250.         currprefs.sound_maxbsiz,
  251.         currprefs.sound_minbsiz);
  252. #endif
  253.     if (currprefs.fake_joystick)
  254.     fprintf (f, "-J %c%c\n", "01MABC"[currprefs.fake_joystick & 255],
  255.         "01MABC"[(currprefs.fake_joystick >> 8) & 255]);
  256.     fprintf (f, "-f %d\n", currprefs.framerate);
  257.     fprintf (f, "-O %d:%d:", currprefs.gfx_width, currprefs.gfx_height);
  258.     if (currprefs.gfx_lores)
  259.     fprintf (f, "l");
  260.     switch (currprefs.gfx_xcenter) {
  261.      case 1: fprintf (f, "x"); break;
  262.      case 2: fprintf (f, "X"); break;
  263.      default: break;
  264.     }
  265.     switch (currprefs.gfx_ycenter) {
  266.      case 1: fprintf (f, "y"); break;
  267.      case 2: fprintf (f, "Y"); break;
  268.      default: break;
  269.     }
  270.     if (currprefs.gfx_linedbl)
  271.     fprintf (f, "d");
  272.     if (currprefs.gfx_correct_aspect)
  273.     fprintf (f, "c");
  274.     fprintf (f, "\n-H %d\n", currprefs.color_mode);
  275.     if (fastmem_size > 0)
  276.     fprintf (f, "-F %d\n", fastmem_size / 0x100000);
  277.     if (z3fastmem_size > 0)
  278.     fprintf (f, "-Z %d\n", z3fastmem_size / 0x100000);
  279.     if (bogomem_size > 0)
  280.     fprintf (f, "-s %d\n", bogomem_size / 0x40000);
  281.     if (gfxmem_size > 0)
  282.     fprintf (f, "-U %d\n", gfxmem_size / 0x100000);
  283.     fprintf (f, "-c %d\n", chipmem_size / 0x80000);
  284. #if CPU_LEVEL > 1
  285.     fprintf (f, "-4 %d\n", address_space_24);
  286. #endif
  287.     if (!currprefs.automount_uaedev)
  288.     fprintf (f, "-a\n");
  289.     if (currprefs.use_low_bandwidth)
  290.     fprintf (f, "-L\n");
  291.     if (currprefs.use_mitshm)
  292.     fprintf (f, "-T\n");
  293.     fprintf (f, "-w %d\n", currprefs.m68k_speed);
  294.     fprintf (f, "-A %d\n", currprefs.emul_accuracy);
  295.     /* We don't write "-t" - I can hardly imagine a user who wants that in his
  296.      * config file. */
  297.     write_filesys_config(f);
  298. #ifndef UNSUPPORTED_OPTION_l
  299.     fprintf (f, "-l %s\n", (currprefs.keyboard_lang == KBD_LANG_DE ? "de"
  300.                : currprefs.keyboard_lang == KBD_LANG_ES ? "es"
  301.                : currprefs.keyboard_lang == KBD_LANG_US ? "us"
  302.                : currprefs.keyboard_lang == KBD_LANG_SE ? "se"
  303.                : currprefs.keyboard_lang == KBD_LANG_FR ? "fr"
  304.                : currprefs.keyboard_lang == KBD_LANG_IT ? "it"
  305.                : "FOO"));
  306. #endif
  307. }
  308.  
  309. struct optiondef {
  310.     const char *getopt_str;
  311.     const char *helpstr;
  312. };
  313.  
  314.  
  315. static struct optiondef uaeopts[] = {
  316.     { "h",      "  -h           : Print help\n" },
  317. #ifndef UNSUPPORTED_OPTION_l
  318.     { "l:",      "  -l lang      : Set keyboard language to lang, where lang is\n"
  319.           "                 DE, SE, US, ES, FR or IT\n" },
  320. #endif
  321.     { "m:",      "  -m VOL:dir   : Mount directory called <dir> as AmigaDOS volume VOL:\n" },
  322.     { "M:",      "  -M VOL:dir   : like -m, but mount read-only\n" },
  323.     { "W:",      "  -W specs     : Mount a hardfile. The \"specs\" parameter consists of\n"
  324.           "                 \"sectors per track:number of surfaces:filename\"\n" },
  325.     { "s:",      "  -s n         : Emulate n*256 KB slow memory at 0xC00000\n" },
  326.     { "c:",      "  -c n         : Emulate n*512 KB chip memory at 0x000000\n" },
  327.     { "F:",      "  -F n         : Emulate n MB fast memory at 0x200000\n" },
  328.     { "Z:",      "  -Z n         : Emulate n MB Zorro III fast memory\n" },
  329. #if CPU_LEVEL > 1 && defined PICASSO96
  330.     { "U:",      "  -U n         : Emulate a Picasso96 compatible graphics card with n MB memory\n" },
  331. #endif
  332. #if CPU_LEVEL > 1
  333.     { "4:",       "  -4 n         : Select a 24 bit (n = 1) or 32 bit (n = 0) address space\n" },
  334. #endif
  335.     { "w:",      "  -w n         : Set CPU speed to n (default 4)\n" },
  336.     { "a",      "  -a           : Add no expansion devices (disables fastmem and\n"
  337.           "                 harddisk support\n" },
  338.     { "J:",      "  -J xy        : Specify how to emulate joystick port 0 (x) and 1 (y)\n"
  339.           "                 Use 0 for joystick 0, 1 for joystick 1, M for mouse,\n"
  340.           "                 a/b/c for various keyboard replacements\n" },
  341.     { "f:",      "  -f n         : Set the frame rate to 1/n (draw only every nth frame)\n" },
  342. #ifndef UNSUPPORTED_OPTION_D
  343.     { "D",      "  -D           : Start up the built-in debugger\n" },
  344. #endif
  345.     { "i",      "  -i           : Print illegal memory accesses\n" },
  346.     { "t",      "  -t           : Test drawing speed (makes the emulator very slow)\n" },
  347. #ifndef UNSUPPORTED_OPTION_o
  348.     { "o",      "  -o           : Allow options to be saved\n" },
  349. #endif
  350. #ifndef UNSUPPORTED_OPTION_G
  351.     { "G",      "  -G           : Disable user interface\n" },
  352. #endif
  353.     { "A:",      "  -A n         : Set emulator accuracy to n (0, 1 or 2)\n" },
  354. #ifdef USE_EXECLIB
  355.     { "g",      "  -g           : Turn on gfx-lib replacement (EXPERIMENTAL).\n" },
  356. #endif
  357.     { "C:",      "  -C hpos      : Adjust copper emulation (default -1)\n" },
  358.     { "n:",      "  -n parms     : Set blitter parameters: 'i' enables immediate blits,\n"
  359.           "                 '3' enables 32 bit blits (may crash RISC machines)\n" },
  360.     { "0:1:2:3:", "  -[0123] file : Use file instead of df[0123].adf as disk image\n" },
  361.     { "r:",      "  -r file      : Use file as ROM image instead of kick.rom\n" },
  362.     { "K:",      "  -K file      : Use file as ROM key file for encrypted ROMs.\n" },
  363. #ifndef UNSUPPORTED_OPTION_S
  364.     { "S:",      "  -S spec      : Set parameters for sound emulation (see below)\n" },
  365. #endif
  366. #ifndef UNSUPPORTED_OPTION_p
  367.     { "p:",      "  -p prt       : Use <prt> for printer output (default " DEFPRTNAME ").\n" },
  368. #endif
  369. #ifndef UNSUPPORTED_OPTION_I
  370.     { "I:",      "  -I device    : Use <device> for serial output (e.g. " DEFSERNAME ").\n" },
  371.     { "d:",       "  -d [s][p]    : Open serial/parallel port on demand only.\n" },
  372. #endif
  373. #ifdef TARGET_SPECIAL_OPTIONS
  374.     TARGET_SPECIAL_OPTIONS
  375. #endif
  376.     { "O:",      "  -O modespec  : Define graphics mode (see below)\n" },
  377.     { "H:",      "  -H mode      : Set the color mode (see below)\n" }
  378. };
  379.  
  380. void usage(void)
  381. {
  382.     int i;
  383.  
  384.     printf ("UAE - The Un*x Amiga emulator\n");
  385.     printf ("Summary of command-line options (please read the README for more details):\n");
  386.     for (i = 0; i < sizeof uaeopts / sizeof *uaeopts; i++)
  387.     printf ("%s", uaeopts[i].helpstr);
  388.  
  389.     printf ("\n");
  390.     printf ("%s",
  391.        "The format for the \"-S\" sound spec parameter is as follows:\n"
  392.        "  -S enable:stereo:bits:freq:maxbuffer:minbuffer\n"
  393.        "  You do not need to give the full specs, you can terminate after every field.\n"
  394.        "  enable: Either 0 (no sound), 1 (emulated, but not output), 2 (emulated), or\n"
  395.        "    3 (completely accurate emulation). The suggested value is 2.\n"
  396.        "  stereo: Either 's' (stereo) or 'm' (mono).\n"
  397.        "  bits: Number of bits to use for sound output, usually 8 or 16\n"
  398.        "  freq: Frequency for sound output; usually 44100 or 22050\n"
  399.        "  maxbuffer: Maximum buffer size for sound output\n"
  400.        "  minbuffer: Minimum buffer size for sound output\n"
  401.        "Larger buffers need less computing power, but the sound will be delayed.\n"
  402.        "Some of these settings will have no effect on certain ports of UAE.\n");
  403.     printf ("%s",
  404. #ifndef COLOR_MODE_HELP_STRING
  405.        "Valid color modes: 0 (256 colors); 1 (32768 colors); 2 (65536 colors)\n"
  406.        "                   3 (256 colors, with dithering for better results)\n"
  407.        "                   4 (16 colors, dithered); 5 (16 million colors)\n"
  408. #else
  409.        COLOR_MODE_HELP_STRING
  410. #endif
  411.        );
  412.     printf ("%s",
  413.        "The format for the modespec parameter of \"-O\" is as follows:\n"
  414.        "  -O width:height:modifiers\n"
  415.        "  \"width\" and \"height\" specify the dimensions of the picture.\n"
  416.        "  \"modifiers\" is a string that contains zero or more of the following\n"
  417.        "  characters:\n"
  418.        "   l:    Treat the display as lores, drawing only every second pixel\n"
  419.        "   x, y: Center the screen horizontally or vertically.\n"
  420.        "   d:    Doubles the height of the display for better interlace emulation\n"
  421.        "   c:    Correct aspect ratio\n"
  422.        "UAE may choose to ignore the color mode setting and/or adjust the\n"
  423.        "video mode setting to reasonable values.\n");
  424. }
  425.  
  426. static void parse_gfx_specs (char *spec)
  427. {
  428.     char *x0 = my_strdup (spec);
  429.     char *x1, *x2;
  430.  
  431.     x1 = strchr (x0, ':');
  432.     if (x1 == 0)
  433.     goto argh;
  434.     x2 = strchr (x1+1, ':');
  435.     if (x2 == 0)
  436.     goto argh;
  437.     *x1++ = 0; *x2++ = 0;
  438.  
  439.     currprefs.gfx_width = atoi (x0);
  440.     currprefs.gfx_height = atoi (x1);
  441.     currprefs.gfx_lores = strchr (x2, 'l') != 0;
  442.     currprefs.gfx_xcenter = strchr (x2, 'x') != 0 ? 1 : strchr (x2, 'X') != 0 ? 2 : 0;
  443.     currprefs.gfx_ycenter = strchr (x2, 'y') != 0 ? 1 : strchr (x2, 'Y') != 0 ? 2 : 0;
  444.     currprefs.gfx_linedbl = strchr (x2, 'd') != 0;
  445.     currprefs.gfx_correct_aspect = strchr (x2, 'c') != 0;
  446.  
  447.     free (x0);
  448.     return;
  449.  
  450.     argh:
  451.     fprintf (stderr, "Bad display mode specification.\n");
  452.     fprintf (stderr, "The format to use is: \"width:height:modifiers\"\n");
  453.     fprintf (stderr, "Type \"uae -h\" for detailed help.\n");
  454.     free (x0);
  455. }
  456.  
  457. static void parse_sound_spec (char *spec)
  458. {
  459.     char *x0 = my_strdup (spec);
  460.     char *x1, *x2 = NULL, *x3 = NULL, *x4 = NULL, *x5 = NULL;
  461.  
  462.     x1 = strchr (x0, ':');
  463.     if (x1 != NULL) {
  464.     *x1++ = '\0';
  465.     x2 = strchr (x1 + 1, ':');
  466.     if (x2 != NULL) {
  467.         *x2++ = '\0';
  468.         x3 = strchr (x2 + 1, ':');
  469.         if (x3 != NULL) {
  470.         *x3++ = '\0';
  471.         x4 = strchr (x3 + 1, ':');
  472.         if (x4 != NULL) {
  473.             *x4++ = '\0';
  474.             x5 = strchr (x4 + 1, ':');
  475.         }
  476.         }
  477.     }
  478.     }
  479.     currprefs.produce_sound = atoi (x0);
  480.     if (x1) {
  481.     if (*x1 == 's')
  482.         currprefs.stereo = 1;
  483.     else
  484.         currprefs.stereo = 0;
  485.     }
  486.     if (x2)
  487.     currprefs.sound_bits = atoi (x2);
  488.     if (x3)
  489.     currprefs.sound_freq = atoi (x3);
  490.     if (x4)
  491.     currprefs.sound_maxbsiz = currprefs.sound_minbsiz = atoi (x4);
  492.     if (x5)
  493.     currprefs.sound_minbsiz = atoi (x5);
  494.     free (x0);
  495.     return;
  496. }
  497.  
  498. const char *gameport_state (int nr)
  499. {
  500.     if (JSEM_ISJOY0 (nr, currprefs.fake_joystick) && nr_joysticks > 0)
  501.     return "using joystick #0";
  502.     else if (JSEM_ISJOY1 (nr, currprefs.fake_joystick) && nr_joysticks > 1)
  503.     return "using joystick #1";
  504.     else if (JSEM_ISMOUSE (nr, currprefs.fake_joystick))
  505.     return "using mouse";
  506.     else if (JSEM_ISNUMPAD (nr, currprefs.fake_joystick))
  507.     return "using numeric pad as joystick";
  508.     else if (JSEM_ISCURSOR (nr, currprefs.fake_joystick))
  509.     return "using cursor keys as joystick";
  510.     else if (JSEM_ISSOMEWHEREELSE (nr, currprefs.fake_joystick))
  511.     return "using T/F/H/B/Alt as joystick";
  512.  
  513.     return "not connected";
  514. }
  515.  
  516. static int parse_joy_spec (char *spec)
  517. {
  518.     int v0 = 2, v1 = 0;
  519.     if (strlen(spec) != 2)
  520.     goto bad;
  521.  
  522.     switch (spec[0]) {
  523.      case '0': v0 = 0; break;
  524.      case '1': v0 = 1; break;
  525.      case 'M': case 'm': v0 = 2; break;
  526.      case 'A': case 'a': v0 = 3; break;
  527.      case 'B': case 'b': v0 = 4; break;
  528.      case 'C': case 'c': v0 = 5; break;
  529.      default: goto bad;
  530.     }
  531.  
  532.     switch (spec[1]) {
  533.      case '0': v1 = 0; break;
  534.      case '1': v1 = 1; break;
  535.      case 'M': case 'm': v1 = 2; break;
  536.      case 'A': case 'a': v1 = 3; break;
  537.      case 'B': case 'b': v1 = 4; break;
  538.      case 'C': case 'c': v1 = 5; break;
  539.      default: goto bad;
  540.     }
  541.     if (v0 == v1)
  542.     goto bad;
  543.     /* Let's scare Pascal programmers */
  544.     if (0)
  545. bad:
  546.     fprintf (stderr, "Bad joystick mode specification. Use -J xy, where x and y\n"
  547.          "can be 0 for joystick 0, 1 for joystick 1, M for mouse, and\n"
  548.          "a, b or c for different keyboard settings.\n");
  549.  
  550.     return v0 + (v1 << 8);
  551. }
  552.  
  553. static void parse_filesys_spec (int readonly, char *spec)
  554. {
  555.     char buf[256];
  556.     char *s2;
  557.  
  558.     strncpy(buf, spec, 255); buf[255] = 0;
  559.     s2 = strchr(buf, ':');
  560.     if(s2) {
  561.     *s2++ = '\0';
  562. #ifdef __DOS__
  563.     {
  564.         char *tmp;
  565.  
  566.         while ((tmp = strchr(s2, '\\')))
  567.         *tmp = '/';
  568.     }
  569. #endif
  570.     s2 = add_filesys_unit(buf, s2, readonly, 0, 0, 0);
  571.     if (s2)
  572.         fprintf (stderr, "%s\n", s2);
  573.     } else {
  574.     fprintf (stderr, "Usage: [-m | -M] VOLNAME:mount_point\n");
  575.     }
  576. }
  577.  
  578. static void parse_hardfile_spec (char *spec)
  579. {
  580.     char *x0 = my_strdup (spec);
  581.     char *x1, *x2, *x3;
  582.  
  583.     x1 = strchr (x0, ':');
  584.     if (x1 == NULL)
  585.     goto argh;
  586.     *x1++ = '\0';
  587.     x2 = strchr (x1 + 1, ':');
  588.     if (x2 == NULL)
  589.     goto argh;
  590.     *x2++ = '\0';
  591.     x3 = strchr (x2 + 1, ':');
  592.     if (x3 == NULL)
  593.     goto argh;
  594.     *x3++ = '\0';
  595.     x3 = add_filesys_unit (0, x3, 0, atoi (x0), atoi (x1), atoi (x2));
  596.     if (x3)
  597.     fprintf (stderr, "%s\n", x3);
  598.  
  599.     free (x0);
  600.     return;
  601.  
  602.     argh:
  603.     free (x0);
  604.     fprintf (stderr, "Bad hardfile parameter specified - type \"uae -h\" for help.\n");
  605.     return;
  606. }
  607.  
  608. #ifndef DONT_PARSE_CMDLINE
  609.  
  610. void parse_cmdline(int argc, char **argv)
  611. {
  612.     int c, i;
  613.     char getopt_str[256];
  614.     strcpy (getopt_str, "");
  615.  
  616.     for (i = 0; i < sizeof uaeopts / sizeof *uaeopts; i++)
  617.     strcat (getopt_str, uaeopts[i].getopt_str);
  618.  
  619.     /* Help! We're running out of letters! */
  620.     while(((c = getopt(argc, argv, getopt_str)) != EOF))
  621.     switch(c) {
  622.      case 'h': usage();    exit(0);
  623.  
  624.      case '0': strncpy (currprefs.df[0], optarg, 255); currprefs.df[0][255] = 0; break;
  625.      case '1': strncpy (currprefs.df[1], optarg, 255); currprefs.df[1][255] = 0; break;
  626.      case '2': strncpy (currprefs.df[2], optarg, 255); currprefs.df[2][255] = 0; break;
  627.      case '3': strncpy (currprefs.df[3], optarg, 255); currprefs.df[3][255] = 0; break;
  628.      case 'r': strncpy (romfile, optarg, 255); romfile[255] = 0; break;
  629.      case 'K': strncpy (keyfile, optarg, 255); keyfile[255] = 0; break;
  630.      case 'p': strncpy (prtname, optarg, 255); prtname[255] = 0; break;
  631.      case 'I': strncpy (sername, optarg, 255); sername[255] = 0; currprefs.use_serial = 1; break;
  632.      case 'm': case 'M': parse_filesys_spec (c == 'M', optarg); break;
  633.      case 'W': parse_hardfile_spec (optarg); break;
  634.      case 'S': parse_sound_spec (optarg); break;
  635.      case 'f': currprefs.framerate = atoi (optarg); break;
  636.      case 'A': currprefs.emul_accuracy = atoi (optarg); break;
  637.      case 'x': currprefs.no_xhair = 1; break;
  638.      case 'i': currprefs.illegal_mem = 1; break;
  639.      case 'J': currprefs.fake_joystick = parse_joy_spec (optarg); break;
  640.      case 'a': currprefs.automount_uaedev = 0; break;
  641.      case 'o': currprefs.allow_save = 1; break;
  642.      case 't': currprefs.test_drawing_speed = 1; break;
  643.      case 'L': currprefs.use_low_bandwidth = 1; break;
  644.      case 'T': currprefs.use_mitshm = 1; break;
  645.      case 'w': currprefs.m68k_speed = atoi (optarg); break;
  646.  
  647.      case 'g': use_gfxlib = 1; break;
  648.      case 'G': no_gui = 1; break;
  649.      case 'D': use_debugger = 1; break;
  650.  
  651.      case 'n':
  652.     if (strchr (optarg, '3') != 0)
  653.         currprefs.blits_32bit_enabled = 1;
  654.     if (strchr (optarg, 'i') != 0)
  655.         currprefs.immediate_blits = 1;
  656.     break;
  657.  
  658.      case 'C':
  659.     currprefs.copper_pos = atoi (optarg);
  660.     break;
  661.  
  662.      case 'Z':
  663.     z3fastmem_size = atoi (optarg) * 0x100000;
  664.     break;
  665.  
  666.      case 'U':
  667.     gfxmem_size = atoi (optarg) * 0x100000;
  668.     break;
  669.  
  670.      case 'F':
  671.     fastmem_size = atoi (optarg) * 0x100000;
  672.     break;
  673.  
  674.      case 's':
  675.     bogomem_size = atoi (optarg) * 0x40000;
  676.     break;
  677.  
  678.      case 'c':
  679.     chipmem_size = atoi (optarg) * 0x80000;
  680.     break;
  681.  
  682.      case '4':
  683.     address_space_24 = atoi (optarg);
  684.     break;
  685.  
  686.      case 'l':
  687.     if (0 == strcasecmp(optarg, "de"))
  688.         currprefs.keyboard_lang = KBD_LANG_DE;
  689.     else if (0 == strcasecmp(optarg, "us"))
  690.         currprefs.keyboard_lang = KBD_LANG_US;
  691.     else if (0 == strcasecmp(optarg, "se"))
  692.         currprefs.keyboard_lang = KBD_LANG_SE;
  693.     else if (0 == strcasecmp(optarg, "fr"))
  694.         currprefs.keyboard_lang = KBD_LANG_FR;
  695.     else if (0 == strcasecmp(optarg, "it"))
  696.         currprefs.keyboard_lang = KBD_LANG_IT;
  697.     else if (0 == strcasecmp(optarg, "es"))
  698.         currprefs.keyboard_lang = KBD_LANG_ES;
  699.     break;
  700.  
  701.      case 'O': parse_gfx_specs (optarg); break;
  702.      case 'd':
  703.     if (strchr (optarg, 'S') != NULL || strchr (optarg, 's')) {
  704.         write_log ("  Serial on demand.\n");
  705.         currprefs.serial_demand = 1;
  706.     }
  707.     if (strchr (optarg, 'P') != NULL || strchr (optarg, 'p')) {
  708.         write_log ("  Parallel on demand.\n");
  709.         currprefs.parallel_demand = 1;
  710.     }
  711.  
  712.     break;
  713.  
  714.      case 'H':
  715.     currprefs.color_mode = atoi (optarg);
  716.     if (currprefs.color_mode < 0) {
  717.         fprintf (stderr, "Bad color mode selected. Using default.\n");
  718.         currprefs.color_mode = 0;
  719.     }
  720.     break;
  721.     }
  722. }
  723. #endif
  724.  
  725. static void parse_cmdline_and_init_file(int argc, char **argv)
  726. {
  727.     FILE *f;
  728.     char *tmp;
  729.     int t;
  730.     char *buffer,*tmpbuf, *token;
  731.     char smallbuf[256];
  732.     int bufsiz, result;
  733.     int n_args;
  734.     char **new_argv;
  735.     int new_argc;
  736.     char *home;
  737.  
  738.     strcpy(optionsfile,"");
  739.  
  740. #ifdef OPTIONS_IN_HOME
  741.     home = getenv("HOME");
  742.     if (home != NULL && strlen(home) < 240)
  743.     {
  744.     strcpy(optionsfile, home);
  745.     strcat(optionsfile, "/");
  746.     }
  747. #endif
  748.  
  749.     strcat(optionsfile, OPTIONSFILENAME);
  750.  
  751.     f = fopen(optionsfile, "rb");
  752. #ifdef OPTIONS_IN_HOME
  753.     /* sam: if not found in $HOME then look in current directory */
  754.     if (f == NULL) {
  755.     strcpy (optionsfile, OPTIONSFILENAME);
  756.     f = fopen(optionsfile, "rb");
  757.     }
  758. #endif
  759.  
  760.     if (f == NULL) {
  761.     parse_cmdline(argc, argv);
  762.     return;
  763.     }
  764.     fseek(f, 0, SEEK_END);
  765.     bufsiz = ftell(f);
  766.     fseek(f, 0, SEEK_SET);
  767.  
  768.     buffer = (char *)malloc(bufsiz+1);
  769.     buffer[bufsiz] = 0;
  770.     if (fread (buffer, 1, bufsiz, f) < bufsiz) {
  771.     fprintf (stderr, "Error reading configuration file\n");
  772.     fclose (f);
  773.     parse_cmdline (argc, argv);
  774.     return;
  775.     }
  776.     fclose(f);
  777.  
  778.     /* Canonicalize the buffer */
  779.     while ((tmp = strchr (buffer, '\r')))
  780.     *tmp = ' ';
  781.     for (;;) {
  782.     tmp = strchr (buffer, '\n');
  783.     if (tmp == 0)
  784.         break;
  785.     if (tmp[1] == '#') {
  786.         char *tmp2 = strchr (tmp + 1, '\n');
  787.         if (tmp2 == 0)
  788.         *tmp = '\0';
  789.         else
  790.         memmove (tmp, tmp2, strlen (tmp2) + 1);
  791.     } else {
  792.         *tmp = ' ';
  793.     }
  794.     }
  795.     while ((tmp = strchr(buffer, '\t')))
  796.     *tmp = ' ';
  797.  
  798.     tmp = buffer;
  799.     while (*tmp == ' ')
  800.     tmp++;
  801.     t = strlen (tmp);
  802.     memmove (buffer, tmp, t + 1);
  803.  
  804.     while (t > 0 && buffer[t-1] == ' ')
  805.     buffer[--t] = '\0';
  806.     for (;;) {
  807.     tmp = strstr (buffer, "  ");
  808.     if (tmp == 0)
  809.         break;
  810.     memmove (tmp, tmp + 1, strlen (tmp));
  811.     }
  812.  
  813.     tmpbuf = my_strdup (buffer);
  814.  
  815.     n_args = 0;
  816.     if (strtok(tmpbuf, "\n ") != NULL) {
  817.     do {
  818.         n_args++;
  819.     } while (strtok(NULL, "\n ") != NULL);
  820.     }
  821.     free (tmpbuf);
  822.  
  823.     new_argv = (char **)malloc ((1 + n_args + argc) * sizeof (char **));
  824.     new_argv[0] = argv[0];
  825.     new_argc = 1;
  826.  
  827.     token = strtok(buffer, "\n ");
  828.     while (token != NULL) {
  829.     new_argv[new_argc] = my_strdup (token);
  830.     new_argc++;
  831.     token = strtok(NULL, "\n ");
  832.     }
  833.     for (n_args = 1; n_args < argc; n_args++)
  834.     new_argv[new_argc++] = argv[n_args];
  835.     new_argv[new_argc] = NULL;
  836.     parse_cmdline(new_argc, new_argv);
  837. }
  838.  
  839. /* Okay, this stuff looks strange, but it is here to encourage people who
  840.  * port UAE to re-use as much of this code as possible. Functions that you
  841.  * should be using are do_start_program() and do_leave_program(), as well
  842.  * as real_main(). Some OSes don't call main() (which is braindamaged IMHO,
  843.  * but unfortunately very common), so you need to call real_main() from
  844.  * whatever entry point you have. You may want to write your own versions
  845.  * of start_program() and leave_program() if you need to do anything special.
  846.  * Add #ifdefs around these as appropriate.
  847.  */
  848.  
  849. void do_start_program(void)
  850. {
  851.     /* Do a reset on startup. Whether this is elegant is debatable. */
  852.     quit_program = 2;
  853.     m68k_go(1);
  854. }
  855.  
  856. void do_leave_program(void)
  857. {
  858.     graphics_leave();
  859.     close_joystick();
  860.     close_sound();
  861.     dump_counts();
  862.     serial_exit();
  863.     zfile_exit();
  864.     if (!no_gui)
  865.     gui_exit();
  866. }
  867.  
  868. #ifndef _WIN32
  869. void start_program(void)
  870. {
  871.     do_start_program();
  872. }
  873. #endif
  874.  
  875. void leave_program(void)
  876. {
  877.     do_leave_program();
  878. }
  879.  
  880. void real_main(int argc, char **argv)
  881. {
  882.     FILE *hf;
  883.  
  884.     if (!graphics_setup()) {
  885.     exit(1);
  886.     }
  887.  
  888.     rtarea_init ();
  889.     hardfile_install ();
  890.  
  891.     parse_cmdline_and_init_file(argc, argv);
  892.  
  893.     machdep_init();
  894.  
  895.     if (!setup_sound()) {
  896.     fprintf (stderr, "Sound driver unavailable: Sound output disabled\n");
  897.     currprefs.produce_sound = 0;
  898.     }
  899.     init_joystick();
  900.  
  901.     if (!no_gui) {
  902.     int err = gui_init();
  903.     if (err == -1) {
  904.         fprintf (stderr, "Failed to initialize the GUI\n");
  905.     } else if (err == -2) {
  906.         exit(0);
  907.     }
  908.     }
  909.     if (sound_available && !init_sound()) {
  910.     fprintf (stderr, "Sound driver unavailable: Sound output disabled\n");
  911.     currprefs.produce_sound = 0;
  912.     }
  913.  
  914.     fix_options();
  915.     changed_prefs = currprefs;
  916.  
  917.     /* Install resident module to get 8MB chipmem, if requested */
  918.     rtarea_setup();
  919.  
  920.     keybuf_init(); /* Must come after init_joystick */
  921.  
  922.     expansion_init ();
  923.     memory_init();
  924.  
  925.     filesys_install();
  926.     gfxlib_install();
  927.     emulib_install();
  928.     uaeexe_install();
  929.  
  930.     custom_init(); /* Must come after memory_init */
  931.     serial_init();
  932.     DISK_init();
  933.     init_m68k();
  934.     compiler_init();
  935.     gui_update();
  936.  
  937.     if (graphics_init ()) {
  938.     setup_brkhandler ();
  939.     filesys_start_threads ();
  940.     if (use_debugger && debuggable ())
  941.         activate_debugger ();
  942.  
  943.     start_program ();
  944.     }
  945.     leave_program ();
  946. }
  947.  
  948. #ifndef NO_MAIN_IN_MAIN_C
  949. int main(int argc, char **argv)
  950. {
  951.     real_main(argc, argv);
  952.     return 0;
  953. }
  954. #endif
  955.